package gpar; 

import gpar.io.Io;

import java.util.Hashtable;
import java.util.ArrayList;
import java.util.List;

/** Holds all the settings,*/
public class Settings
{

    public static String[] possibleMathOperators = { "+", "-", "/", "*" };
    public static String[] possibleMathCalls = { "getDistanceRemaining()", 
        "getHeadingRadians()", "getGunHeadingRadians()", "getRadarHeadingRadians()", 
        "getGunTurnRemainingRadians()", "getRadarTurnRemainingRadians()", 
        "getTurnRemainingRadians()" };

    public static String[] possibleBooleanOperators = { "&&", "||", "==", "!="};
    // TODO: find out which robocode method calls return a boolean 
    public static String[] possibleBooleanCalls;

    public static String[] eventVariables = {"bulletBearing", "bulletHeading", 
        "enemyBearing", "enemyEnergy", "wallBearing", "enemyEnergy", "enemyBearing", 
        "enemyEnergy", "enemyDistance", "enemyHeading"};
    public static String[][] eventVariablesAndEvents  = 
        {{eventVariables[0], "e.getBearing()", eventVariables[1], "e.getHeading()"},
        {eventVariables[2], "e.getBearing()", eventVariables[3], "e.getEnergy()"},
        {eventVariables[4], "e.getBearing()"},
        {eventVariables[5], "e.getEnergy()"},
        {eventVariables[6], "e.getBearing()", eventVariables[7], "e.getEnergy()", 
            eventVariables[8], "e.getDistance()", eventVariables[9], "e.getHeading()"}};
    public static Hashtable<String, String[]> eventNamesAndVariables;


    public static String[] argumentRequiring0Array =  {"//", "stop();", "resume();"};
    public static String[] argumentRequiring1Array = {"setAhead(", "setFire(", 
        "setTurnLeft(", "setTurnRight(", "setTurnGunLeft(", "setTurnGunRight(", "fire(", 
        "execute(", "setAdjustRadarForRobotTurn(", "setAdjustRadarForGunTurn("};
    public static Hashtable<String, List<List<String>>> grammarHash;



    /** Reads settings from file and fills necessary datastructures, call once! */
    public static void init()
    {
        readSettingsFromFile(Program.CONFIG_FILE);

 
        // load the method names and what variables should be filled in/from the variables
        loadMethodsAndVariables();

        // load the grammar!
        loadGrammar();
    }

    private static void readSettingsFromFile (String configFile)
    {
        Program.println("Reading and setting paramaters from: " + configFile);
        String[] lines = Io.readFileAsLines(configFile);
        for (String line : lines)  
            System.out.println(line);

        //Float.valueOf(lines.get(0).split(delimiter)[1]);
        //Integer.valueOf(lines.get(2).split(delimiter)[1]);

    }



    /** Fills the grammarHash so it can be used. Call once, preferably. {{{ 
    * TERMINAL0: terminates without anything else. 
    * TERMINAL1: terminates with 1 expression tree
    * NONTERMINAL1: continues with 1 grammar (else) 
    * NONTERMINAL2: continues with 1 expression tree and 1 grammar (statements) (other cfs)
    * else..: continue?
    * */
    private static void loadGrammar()
    {
        grammarHash = new Hashtable<String, List<List<String>>>();
    
        // grammar for statements
        ArrayList<List<String>> statementsList = new ArrayList<List<String>> ();
        ArrayList<String> statementsListOption1 = new ArrayList<String>();
        statementsListOption1.add("statement");
        statementsListOption1.add("statements");
        statementsListOption1.add("statement");
        statementsList.add(statementsListOption1);
        grammarHash.put("statements", statementsList);


        // grammar for statement
        ArrayList<List<String>> statementList = new ArrayList<List<String>> ();
        ArrayList<String> statementListOption0 = new ArrayList<String>();
        statementListOption0.add("argumentRequiring0");
        statementList.add(statementListOption0);

        ArrayList<String> statementListOption1 = new ArrayList<String>();
        statementListOption1.add("argumentRequiring1");
        statementList.add(statementListOption1);

        ArrayList<String> statementListOption2 = new ArrayList<String>();
        statementListOption2.add("argumentRequiring2");
        statementList.add(statementListOption2);
        
        ArrayList<String> statementListOption3 = new ArrayList<String>();
        statementListOption3.add("controlFlowStatement");
        statementList.add(statementListOption3);

        grammarHash.put("statement", statementList);


        // grammar for controlFlowStatement
        ArrayList<List<String>> controlFlowStatementList = new ArrayList<List<String>> ();
        ArrayList<String> controlFlowStatementListOption0 = new ArrayList<String>();
        controlFlowStatementListOption0.add("whileStatement"); 
        controlFlowStatementList.add(controlFlowStatementListOption0);

        ArrayList<String> controlFlowStatementListOption1 = new ArrayList<String>();
        controlFlowStatementListOption1.add("ifStatement"); 
        controlFlowStatementList.add(controlFlowStatementListOption1);

        grammarHash.put("controlFlowStatement", controlFlowStatementList);

        
        // grammar for ifStatement
        ArrayList<List<String>> ifStatementList = new ArrayList<List<String>> ();
        ArrayList<String> ifStatementListOption0 = new ArrayList<String>();
        ifStatementListOption0.add("ifStatement"); 
        ifStatementListOption0.add("elseIfStatement"); 
        ifStatementList.add(ifStatementListOption0);

        ArrayList<String> ifStatementListOption1 = new ArrayList<String>();
        ifStatementListOption1.add("if (-NONTERMINAL1");
        ifStatementList.add(ifStatementListOption1);

        grammarHash.put("ifStatement", ifStatementList);
    

        // grammar of elseIfStatement
        ArrayList<List<String>> elseIfStatementList = new ArrayList<List<String>> ();
        ArrayList<String> elseIfStatementListOption0 = new ArrayList<String>();
        elseIfStatementListOption0.add("elseIfStatement"); 
        elseIfStatementListOption0.add("elseIfStatement"); 
        elseIfStatementList.add(elseIfStatementListOption0);

        ArrayList<String> elseIfStatementListOption1 = new ArrayList<String>();
        elseIfStatementListOption1.add("elseIfStatement"); 
        elseIfStatementListOption1.add("elseStatement"); 
        elseIfStatementList.add(elseIfStatementListOption1);

        ArrayList<String> elseIfStatementListOption2 = new ArrayList<String>();
        elseIfStatementListOption2.add("else if (-NONTERMINAL1"); 
        elseIfStatementList.add(elseIfStatementListOption2);

        grammarHash.put("elseIfStatement", elseIfStatementList);

        
        // grammar of whileStatement
        ArrayList<List<String>> whileStatementList= new ArrayList<List<String>> ();
        ArrayList<String> whileStatementListOption0 = new ArrayList<String>();
        whileStatementListOption0.add("while (-NONTERMINAL1"); 
        whileStatementList.add(whileStatementListOption0);
        grammarHash.put("whileStatement", whileStatementList); 


        // grammar of elseStatement
        ArrayList<List<String>> elseStatementList= new ArrayList<List<String>> ();
        ArrayList<String> elseStatementListOption0 = new ArrayList<String>();
        elseStatementListOption0.add("else {-NONTERMINAL0"); 
        elseStatementList.add(elseStatementListOption0);
        grammarHash.put("elseStatement", elseStatementList); 

        
        // grammar of argumentRequiring0 
        ArrayList<List<String>> argumentRequiring0List = new ArrayList<List<String>> ();
        for (String arg : argumentRequiring0Array)
        {
            ArrayList<String> argumentRequiring0ListOptionX = new ArrayList<String>();
            argumentRequiring0ListOptionX.add(arg + "-TERMINAL0"); 
            argumentRequiring0List.add(argumentRequiring0ListOptionX);
        }
        grammarHash.put("argumentRequiring0", argumentRequiring0List); 


        // grammar of argumentRequiring1 
        ArrayList<List<String>> argumentRequiring1List = new ArrayList<List<String>> ();
        for (String arg : argumentRequiring1Array)
        {
            ArrayList<String> argumentRequiring1ListOptionX = new ArrayList<String>();
            argumentRequiring1ListOptionX.add(arg + "-TERMINAL1"); 
            argumentRequiring1List.add(argumentRequiring1ListOptionX);
        }
        grammarHash.put("argumentRequiring1", argumentRequiring1List); 

        // grammar of argumentRequiring2 
        // ArrayList<List<String> argumentRequiring2List = new ArrayList<List<String>> ();
        // for (String arg : argumentRequiring2Array)
        // {
        //     ArrayList<String> argumentRequiring2ListOptionX = new ArrayList<String>();
        //     argumentRequiring2ListOptionX.add(arg + "-TERMINAL"); 
        //     argumentRequiring2List.add(argumentRequiring2ListOptionX);
        // }
        // grammarHash.put("argumentRequiring2", argumentRequiring2List); 

    } // }}}

    /** Loads methods and the variables which should be read from the events from file!{{{*/
    private static void loadMethodsAndVariables()
    {
        String[] nothing = {"int n", "0"};

        // TODO: set default initial capacity and loadFactor correctly!
        eventNamesAndVariables = new Hashtable<String, String[]> ();
        

        eventNamesAndVariables.put("run()", nothing);
        eventNamesAndVariables.put("onHitByBullet(HitByBulletEvent e)", 
            eventVariablesAndEvents[0]);
        eventNamesAndVariables.put("onHitRobot(HitRobotEvent e)", 
            eventVariablesAndEvents[1]);
        eventNamesAndVariables.put("onHitWall(HitWallEvent e)", eventVariablesAndEvents[2]);
        eventNamesAndVariables.put("onBulletHit(BulletHitEvent e)", 
            eventVariablesAndEvents[3] );
        eventNamesAndVariables.put("onBulletMissed(BulletMissedEvent e)", nothing);
        eventNamesAndVariables.put("onBulletHitBullet(BulletHitBulletEvent e)", nothing);
        eventNamesAndVariables.put("onScannedRobot(ScannedRobotEvent e)", 
            eventVariablesAndEvents[4]); 

    }

}
